#include "integer.h"
#include <vector>

OPEN_JLIB_NS


struct Decimal {

  enum class RoundMode : s32 { None = 0, Up, Down, Ceiling, Floor, HalfUp, HalfDown, HalfEven, HalfOdd };

  inline u64 __as_uint64 (double src) noexcept {
    return *(u64*)&src;
  }

  inline Decimal (const Integer& integer, s32 precision, u32 significant) noexcept : _int(integer), _pre(precision), _sig(significant) {
    ++__counter;
  }

  static Integer __pow10 (u32 exp) noexcept;

  static s32 __cmp_half (const Integer& base, const Integer& half) noexcept;

  static Integer __round (const Integer& d, const Integer& q, const Integer& r, RoundMode round, s32 sign_hint);

  static u32 __digit_count (const Integer& num) noexcept;

public:

  Decimal (double src, s32 precision);
  explicit Decimal (const c8* src);
  Decimal (const c8* src, u32 len);

  inline Decimal (const Decimal& other) noexcept : _int(other._int), _pre(other._pre), _sig(other._sig) {
    ++__counter;
  }

  inline ~Decimal () noexcept {
    --__counter;
  }

  inline s32 sign () const noexcept {
    return _int.sign();
  }

  inline s32 precision () const noexcept {
    return _pre;
  };

  inline u32 significant () const noexcept {
    return _sig;
  }

  std::string str (bool sign = false) const noexcept;

  s32 cmp (const Decimal& other) const noexcept;

  Decimal round (s32 precision, RoundMode mode) const noexcept;

  static Decimal div (const Decimal& op1, const Decimal& op2, s32 precision, RoundMode mode);

  Decimal operator+ (const Decimal& other) const noexcept;
  Decimal operator- (const Decimal& other) const noexcept;
  Decimal operator* (const Decimal& other) const noexcept;
  Decimal operator/ (const Decimal& other) const noexcept;

  inline Decimal operator- () const noexcept {
    return {-_int, _pre, _sig};
  }

  inline Decimal abs () const noexcept {
    return {_int.abs(), _pre, _sig};
  }

  inline Decimal pow (u32 exp) const noexcept {
    Integer intr = _int.pow(exp);
    return {intr, s32(_pre * exp), __digit_count(intr)};
  }

  bool operator== (const Decimal& other) const noexcept;
  bool operator!= (const Decimal& other) const noexcept;
  bool operator< (const Decimal& other) const noexcept;
  bool operator<= (const Decimal& other) const noexcept;
  bool operator> (const Decimal& other) const noexcept;
  bool operator>= (const Decimal& other) const noexcept;


public:
  constexpr static s32 MaxCachedTenPower = 256;
  static std::vector<Integer> __pow10s;
  static u64 __counter;
  Integer _int = 0L;
  s32 _pre;
  u32 _sig;
};


inline Decimal operator"" _Dec (const c8* literal) noexcept {
  return Decimal{literal};
}

inline Decimal operator"" _Dec (const c8* literal, uwl length) noexcept {
  return Decimal{literal, u32(length)};
}


CLOSE_JLIB_NS